/**
 *  Copyright (C) 2008-2013  Telosys project org. ( http://www.telosys.org/ )
 *
 *  Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *          http://www.gnu.org/licenses/lgpl.html
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.telosys.common.config; 

import java.io.InputStream;
import java.util.Date;
import java.util.Properties;

import org.telosys.common.TelosysRuntimeException;
import org.telosys.util.ClassUtil;

/**
 * The Telosys configuration ( including the Telosys properties loaded from "telosys.properties" ) 
 * 
 * @author Laurent GUERIN
 * @since 1.2.0
 * 
 */
public class TelosysConfig
{
    //--- Properties names
    public final static String UPLOAD_URL      = "UploadURL" ; 
    public final static String UPLOAD_DIR      = "UploadDir" ; 
    public final static String UPLOAD_CHARSET  = "UploadCharset" ; // v 1.0.5
    public final static String UPLOAD_MAX_SIZE = "UploadMaxSize" ; // v 1.0.5
    
    public final static String SCREEN_CONTEXT_CONVENTION  = "ScreenContext.convention" ; // v 1.0.5
    public final static String SERVICE_PACKAGE_CONVENTION = "Service.package.convention" ; // v 1.0.5
    
    public final static String SERVICE_PARAMETERS_CHARSET = "Service.parameters.charset" ; // v 1.1.1

    public final static String APPLICATION_FACTORY_CLASS_NAME = "FactoryClassName" ; // v 1.2.0
    
    //--- Origin of the properties
    public final static int UNKNOWN    = 0 ;
    public final static int FILESYSTEM = 1 ;
    public final static int WEBAPP     = 2 ;
    public final static int CLASSPATH  = 3 ;
    
    private Properties   _prop  = null ;

    private String       _sFile = null ; // Properties file 
    
    private ConfigLoader _configLoader = null ;
    
    private Date         _initDate     = null ; // Date & time of instance construction
    
    //-----------------------------------------------------------------------------------------
    /**
     * Constructor
     * @param prop the properties
     * @param file the properties file name
     * @param configLoader the configuration loader
     */
    public TelosysConfig(Properties prop, String file, ConfigLoader configLoader)
    {
        super();
        _prop = prop;
        _sFile = file;
        _configLoader = configLoader ;
        _initDate = new Date();
    }
       
    //-----------------------------------------------------------------------------------------
    /**
     * Returns the properties 
     * @return the properties
     */
    public Properties getProperties()
    {
        return _prop;
    }
    
    //-----------------------------------------------------------------------------------------
    /**
     * Returns the properties file name
     * @return the properties file name
     */
    public String getFile()
    {
        return _sFile;
    }

    //-----------------------------------------------------------------------------------------
    /**
     * Returns the properties init date and time
     * @return the creation date of this instance
     */
    public Date getInitDate()
    {
        if ( _initDate != null ) // v 1.1.0
        {
            return new Date( _initDate.getTime() ); // v 1.1.0
        }
        return null ;
    }

    //-----------------------------------------------------------------------------------------
    /**
     * Returns the value of the given property name
     * @param sPropertyName
     * @return the property value or null
     */
    public String getProperty(String sPropertyName) // v 1.0.0
    {
        if ( _prop != null )
        {
            return _prop.getProperty(sPropertyName);
        }
        return null;
    }
    
    //-----------------------------------------------------------------------------------------
    private String getTelosysPropertiesLocation()
    {
        if ( _sFile != null )
        {            
	        int i1 = _sFile.lastIndexOf('/');
	        int i2 = _sFile.lastIndexOf('\\');
	        int i = ( i1 > i2 ? i1 : i2 ) ; // Take the Max
	        if ( i >= 0 )
	        {
	            return _sFile.substring(0,i); // Root without ending '/' or '\'
	        }
	        else
	        {
	            return "" ;
	        }
        }
        return "";
    }
    //-----------------------------------------------------------------------------------------
    private String transformFileName(String sFile)
    {
        if ( sFile == null )
        {
            return null ;
        }
        
        if ( sFile.length() == 0 )
        {
            return sFile ;
        }
        
        //--- If the file name starts with "./" => it's a relative path 
        if ( sFile.startsWith("./") )
        {
            //--- Transform the relative path to full pathe ( ie : "./foo" => "Dir/foo" )
        	// Get the location path for the telosys.properties file ( ie "/aaa/bbb" )
        	String sOriginalLocation = getTelosysPropertiesLocation() ;
        	if ( "".equals(sOriginalLocation ) ) {
        		// No location : just remove "./"
        		return sFile.substring(2) ;
        	}
        	else {
        		// remove "." and concatenate ( ie "/aaaa/bbb" + "/file" or "aaa/bbb" + "/file" )
        		return sOriginalLocation + sFile.substring(1) ; 
        	}
        }
        //--- Not special path => return "as is"
        return sFile ;
    }
    
    //-----------------------------------------------------------------------------------------
    /**
     * Returns the config file name associated with the given property name <br>
     * NB : if the value starts with ".", the "." is replaced by the "telosys.properties" location <br>
     * e.g. : "./myfile" --> "location/myfile"
     * @param sPropertyName : e.g. "ScreensConfFile", "DbConfFile", ... ( see telosys.properties )
     * @return the value 
     */
    private String getConfigFile(String sPropertyName)
    {
        if ( _prop != null )
        {
            String s = _prop.getProperty(sPropertyName);
            if (s != null)
            {
                return transformFileName( s.trim() );
            }
        }
        return null;
    }
    
    //-----------------------------------------------------------------------------------------
    public String toString()
    {
//        String s = "unknown" ;
//        switch(_iOrigin)
//        {
//            case FILESYSTEM : s = "file system" ; break ;
//            case WEBAPP : s = "web application" ; break ;
//            case CLASSPATH : s = "class path" ; break ;
//        }
        return "Telosys properties loaded from '"+_sFile+"' ( origin : " + _configLoader.getOrigin() + " ) at " + _initDate ; 
    }
    //-----------------------------------------------------------------------------------------
    
	private static final String   DB_CONF_FILE       = "DbConfFile";  // v 1.0.0
	
	private static final String   TRACE_CONF_FILE    = "TraceConfFile"; // v 1.0.0
	
	private static final String   TAGS_CONF_FILE     = "TagsConfFile"; // v 1.0.0
	
	private static final String   SCREENS_CONF_FILE  = "ScreensConfFile"; // v 1.0.0
	

    //-----------------------------------------------------------------------------
    /**
     * Returns the InputStream for the resource file associated with the given property name
     * @param sPropertyName
     * @return the input stream or null if the file cannot be opened
     */
    private InputStream getInputStream(String sPropertyName) 
    {
        //$log.trace("getInputStream("+sPropertyName+")");
        String sResource = getConfigFile(sPropertyName); 
        try {
			InputStream is = _configLoader.getInputStream(sResource);
			return is ;
		} catch (Exception e) {
			return null ;
			// TODO Auto-generated catch block
			//e.printStackTrace();
		}
        
//        if ( sResource != null )
//        {
//            int iOrigin = getOrigin(sPropertyName) ;
//            $log.trace("getInputStream("+sPropertyName+") --> '" + sResource + "', origin = " + iOrigin);
//            // Get the input stream for the given resource, using the given origin ( WEBAPP, FILESYSTEM, CLASSPATH )
//            InputStream is = TelosysPropertiesLoader.getInputStream(sResource, iOrigin, $ServletContext );
//            if ( is == null )
//            {
//                $log.error("getInputStream('" + sResource + "') : return NULL" );
//            }
//            return is;
//        }
//        else
//        {
//            return null ;
//        }
    }

    //=============================================================================
    // Factory class 
    //=============================================================================
    /**
     * Returns the name of the specific application factory class if any
     * @return the class name or null if not defined in the 'telosys.properties' file
     */
    public String getApplicationFactoryClassName()
    {
        String sClassName = _prop.getProperty( APPLICATION_FACTORY_CLASS_NAME );
        if ( sClassName != null )
        {
            return sClassName.trim() ;
        }
        return null ;
    }
    
    /**
     * Returns the class of the specific application factory if any
     * @return the class or null if not defined in the 'telosys.properties' file
     */
    public Class<?> getApplicationFactoryClass()
    {
        String sClassName = getApplicationFactoryClassName();
        if ( sClassName != null )
        {
        	Class<?> c = ClassUtil.tryToLoadClass(sClassName);
        	if ( c != null ) {
        		return c ;
        	}
        	else {
        		throw new TelosysRuntimeException("Cannot load class '" + sClassName + "'");
        	}
        }
        return null ;
    }
    
    //=============================================================================
    // Acces to other configuration files/resources
    //=============================================================================
    
    //-----------------------------------------------------------------------------
    // databases.dbcfg  /  dbconfig.xml
    //-----------------------------------------------------------------------------
    /**
     * Returns the file name (or resource name) of the databases XML file ( databases.dbcfg, formerly dbconfig.xml )
     * @return the file or resource name
     */
    public String getDbConfigFileName()
    {
        return getConfigFile(DB_CONF_FILE);
    }
    //-----------------------------------------------------------------------------
    /**
     * Returns the InputStream of the databases XML file or resource ( databases.dbcfg, formerly dbconfig.xml )
     * 
     * @return the InputStream ( or null if cannot get it )
     */
    public InputStream getDbConfigInputStream() 
    {
        return getInputStream(DB_CONF_FILE) ;
    }
    
    //-----------------------------------------------------------------------------
    // screens.xml
    //-----------------------------------------------------------------------------
    /**
     * Returns the file name (or resource name) of the screens XML file ( screens.xml )
     * @return the file or resource name
     */
    public String getScreensConfigFileName()
    {
        return getConfigFile(SCREENS_CONF_FILE);
    }
    //-----------------------------------------------------------------------------
    /**
     * Returns the InputStream of the screens XML file or resource ( screens.xml )
     * 
     * @return the InputStream ( or null if cannot get it )
     */
    public InputStream getScreensConfigInputStream()
    {
        return getInputStream(SCREENS_CONF_FILE) ;
    }

    //-----------------------------------------------------------------------------
    // tags.properties
    //-----------------------------------------------------------------------------
    /**
     * Returns the file name (or resource name) of the tags properties file ( tags.properties ) 
     * @return the file or resource name
     */
    public String getTagsConfigFileName()
    {
        return getConfigFile(TAGS_CONF_FILE); 
    }
    //-----------------------------------------------------------------------------
    /**
     * Returns the InputStream of the tags properties file ( tags.properties ) 
     * @return the InputStream ( or null if cannot get it )
     */
    public InputStream getTagsConfigInputStream()
    {
        return getInputStream(TAGS_CONF_FILE) ; 
    }
    
    //-----------------------------------------------------------------------------
    // traces.properties
    //-----------------------------------------------------------------------------
    /**
     * Returns the file name (or resource name) of the trace properties file ( traces.properties ) 
     * @return the file or resource name
     */
    public String getTraceConfigFileName()
    {
        return getConfigFile(TRACE_CONF_FILE); 
    }
    //-----------------------------------------------------------------------------
    /**
     * Returns the InputStream of the trace properties file ( traces.properties ) 
     * @return the InputStream ( or null if cannot get it )
     */
    public InputStream getTraceConfigInputStream()
    {
        return getInputStream(TRACE_CONF_FILE); 
    }
    
    
}
